home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume9 / dtree < prev    next >
Encoding:
Text File  |  1989-12-20  |  34.5 KB  |  1,356 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v09i085: dtree
  3. From: djm@abyss.eng.umd.edu (David J. MacKenzie)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 9, Issue 85
  7. Submitted-by: djm@abyss.eng.umd.edu (David J. MacKenzie)
  8. Archive-name: dtree
  9.  
  10. This is a new revision of the dtree Unix directory tree printing
  11. program.  Its output has a different, and in my opinion more
  12. attractive, format from that of the vtree program that appeared in
  13. comp.sources.unix volume 18.
  14.  
  15. This version of dtree should work on all Unixes from version 7 onward,
  16. with some tweaking of the Makefile.
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of shell archive."
  25. # Contents:  README dtree.1 dtree.c getcwd.c Makefile
  26. # Wrapped by djm@abyss on Wed Dec 20 15:14:15 1989
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'README' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'README'\"
  30. else
  31. echo shar: Extracting \"'README'\" \(1014 characters\)
  32. sed "s/^X//" >'README' <<'END_OF_FILE'
  33. Xdtree pretty-prints directory structures like this:
  34. X
  35. X      |-df---------
  36. X      |-ftw--------
  37. X      |
  38. X      |            |-bin-src-
  39. X      |            |-date----
  40. X      |-gnu--------|-install-
  41. X      |            |-lib-----
  42. X|-src-|            |-libc----
  43. X      |            |-tput----
  44. X      |-misc-------
  45. X      |-patches----
  46. X      |-printf-----
  47. X      |-qterm------
  48. X
  49. XIt was originally written for v7 and 4.1BSD; a version that had been
  50. Xpartially adapted to the Berkeley Fast File System and portable
  51. Xdirectory package appeared in mod.sources several years ago, but it
  52. Xhad several bugs (among the more severe, it always dumps core on some
  53. Xsystems).  This version fixes those and also has improved performance
  54. Xand more helpful error messages.  It also works on System V; for the
  55. Xbenefit of System V users, I have packaged with dtree Doug Gwyn's free
  56. Xreimplementation of the getcwd function that doesn't open a pipe to
  57. X/bin/pwd but determines the current directory directly; this should
  58. Xhelp performance on those systems.
  59. END_OF_FILE
  60. if test 1014 -ne `wc -c <'README'`; then
  61.     echo shar: \"'README'\" unpacked with wrong size!
  62. fi
  63. # end of 'README'
  64. fi
  65. if test -f 'dtree.1' -a "${1}" != "-c" ; then 
  66.   echo shar: Will not clobber existing file \"'dtree.1'\"
  67. else
  68. echo shar: Extracting \"'dtree.1'\" \(2365 characters\)
  69. sed "s/^X//" >'dtree.1' <<'END_OF_FILE'
  70. X.TH DTREE 1L
  71. X.SH NAME
  72. Xdtree \- display directory tree structures
  73. X.SH SYNOPSIS
  74. X.B dtree
  75. X[
  76. X.I \-adfgHlnpsvx
  77. X] [
  78. X.I \-c linelength
  79. X] [
  80. X.BR directory ...
  81. X]
  82. X.SH DESCRIPTION
  83. X.I dtree
  84. Xdisplays a graphic representation of the directory structure of each given
  85. X.B directory 
  86. Xand its children. If no directories are specified, the current
  87. Xdirectory is used.
  88. XBy default, only
  89. Xdirectories, not regular files, are shown, and only their
  90. Xfilenames are given.  Various options add additional
  91. Xinformation to the tree.
  92. X.SS OPTIONS
  93. X.TP
  94. X.I \-a
  95. XInclude files in the listing (excluding entries beginning with '.').
  96. X.TP
  97. X.I \-c linelength
  98. XMake
  99. X.I linelength
  100. Xthe length of each
  101. Xcolumn of the printout.  By default, this is 14.
  102. XAny entries longer than
  103. Xthe column length are truncated accordingly, and the last character that
  104. Xfits into the column is replaced by an asterisk.
  105. XThis option only has an effect if the
  106. X.I -v 
  107. Xoption is specified.
  108. X.TP
  109. X.I \-d
  110. XList directories first.  For each directory, its subdirectories
  111. Xwill be listed first, and then all of its other entries.
  112. X.TP
  113. X.I \-f
  114. XList files first.  The reverse of
  115. X.IR  \-d .
  116. X.TP
  117. X.I \-l
  118. XLong listing.  Display useful information to the right of
  119. Xeach entry: the name of the file's owner, its size in blocks, and its mode.
  120. X.TP
  121. X.I \-g
  122. XSame as the
  123. X.I \-l
  124. Xoption, except that the group name is used instead of
  125. Xthe owner name.  If both the
  126. X.I \-l
  127. Xand
  128. X.I \-g
  129. Xoptions are used, both the
  130. Xowner and group will be displayed.
  131. X.TP
  132. X.I \-H
  133. XDisplay a header at the top of the printout that gives the time and
  134. Xdate that the printout was made and a summary of the type of
  135. Xinformation contained in the tree.
  136. X.TP
  137. X.I \-n
  138. XNo sort.  Entries are listed in the order they are read
  139. Xfrom the directories.
  140. X.TP
  141. X.I \-p
  142. XInclude entries beginning with '.' (except '.' and '..').
  143. X.TP
  144. X.I \-s
  145. XSimplify the long listing: display the user id, size in blocks, and
  146. Xoctal mode of the file.  This option implies the
  147. X.I \-l
  148. Xoption unless the
  149. X.I \-g
  150. Xoption is specified.
  151. X.TP
  152. X.I \-v
  153. XDo not let column lengths vary; use the same
  154. Xwidth for each column of output.  The width defaults to 14
  155. Xbut can be set with the
  156. X.I \-c
  157. Xoption.
  158. X.TP
  159. X.I \-x
  160. XDo not cross file systems.  
  161. X.I dtree
  162. Xwill not cross over to a
  163. Xsubdirectory if it is on a different file system.
  164. X.SH AUTHOR
  165. XDave Borman, Digital Unix Engineering Group
  166. X.br
  167. Xdecvax!borman
  168. X.br
  169. XOriginally written at St. Olaf College, Northfield, MN.
  170. END_OF_FILE
  171. if test 2365 -ne `wc -c <'dtree.1'`; then
  172.     echo shar: \"'dtree.1'\" unpacked with wrong size!
  173. fi
  174. # end of 'dtree.1'
  175. fi
  176. if test -f 'dtree.c' -a "${1}" != "-c" ; then 
  177.   echo shar: Will not clobber existing file \"'dtree.c'\"
  178. else
  179. echo shar: Extracting \"'dtree.c'\" \(21819 characters\)
  180. sed "s/^X//" >'dtree.c' <<'END_OF_FILE'
  181. X/*
  182. X *    DTREE - Print the tree structure of a directory
  183. X *    4/7/83 name was changed from TREE to DTREE
  184. X *    9/7/83 mods for 4.1c and 4.2 dirctory structure added
  185. X *
  186. X *    Dave Borman, Digital Unix Engineering Group
  187. X *        decvax!borman
  188. X *    Originally written at St. Olaf College, Northfield MN.
  189. X *    Copyright (c) 1983 by Dave Borman
  190. X *    All rights reserved
  191. X *    This program may not be sold, but may be distributed
  192. X *    provided this header is included.
  193. X *
  194. X *    Usage:    dtree [-adfgHlnpsvx] [-c line-length] [directory...]
  195. X *    Flags:    -a) include non-directory entries in listing
  196. X *        -d) sort tree with directories at the top
  197. X *        -f) sort tree with files at the top
  198. X *        -g) same as l, but use group name instead of user name
  199. X *        -H) display a header at top
  200. X *        -l) print stats with each listing
  201. X *            if both g & l flags are given, both owner and
  202. X *            group will be printed
  203. X *        -n) do not sort the tree
  204. X *        -p) include files starting with a '.' (except "." & "..")
  205. X *        -s) use shorter stats. Implies -l if -g isn't given.
  206. X *        -v) variable length columns off
  207. X *        -x) do not cross mounted file systems.
  208. X *        -c length) set max column length to "length"
  209. X */
  210. X
  211. X /*     Modified by      Ed Arnold      CSU-CS   (csu-cs!arnold)     3-5-84
  212. X  *
  213. X  *     Allows symbolic links to both directories and individual files.
  214. X  *     With a '-l' or '-al' option, links are denoted with a 'l' in front of 
  215. X  *     file or directory permissions. In all other instances both links to 
  216. X  *     directories and files are represented just as files are. Contents of
  217. X  *     linked directories are not printed due to the possibility of 
  218. X  *     recursively linked directories.
  219. X  *
  220. X  *     Big directory name option added by:
  221. X  *                      Mike Vevea      CSU-CS (csu-cs!vevea)      3-22-84
  222. X  *
  223. X  *    Toggle sense of -v (running 4.2), and eliminate some extraneous
  224. X  *        print info    Mike Meyer Energy Analysts (mwm@ea)    4/17/84
  225. X  *
  226. X  *    Fix the exit status to correctly indicate what happened.
  227. X  *                Mike Meyer Energy Analysts (mwm@ea)    4/23/84
  228. X  *
  229. X  *    Change MAX to INITIAL_ELEM to fix conflict on Suns,
  230. X  *    fix incorrect default value for Clength when -v not given,
  231. X  *    add -H option to print header with date and description of tree,
  232. X  *    remove -b option (useless) and simplify array access,
  233. X  *    use getopt to parse options, fix usage message,
  234. X  *    use getwd instead of opening a pipe to pwd,
  235. X  *    make error messages more informative,
  236. X  *    use strncpy instead of sprintf for speed,
  237. X  *    move function declarations to top of file,
  238. X  *    comment out junk after #else and #endif,
  239. X  *    make symbolic link configuring automatic,
  240. X  *    check all error returns from malloc and realloc,
  241. X  *    add System V/Xenix/Unos compatibility,
  242. X  *    remove definition of rindex.
  243. X  *        David MacKenzie <djm@eng.umd.edu> 12/20/89
  244. X  */
  245. X
  246. X/* Compile-time options:
  247. X *
  248. X * STATS    leave undefined to remove stats, giving more core space
  249. X * and thus the ability to tree larger tree structures on PDP 11/70s.
  250. X *
  251. X * NEWDIR    directory structure a la Berkeley 4.1c or 4.2
  252. X *
  253. X * NDIR        use <sys/ndir.h> instead of <sys/dir.h>
  254. X * NEWDIR must be defined as well.
  255. X *
  256. X * DIRENT    use Posix directory library.
  257. X * NEWDIR must be defined as well.
  258. X *
  259. X * SYSV        use getcwd instead of getwd, strrchr instead of rindex.
  260. X */
  261. X
  262. Xstatic    char Sccsid[]="@(#)dtree.c    2.3    2/14/84";
  263. X
  264. X#ifdef S_IFLNK
  265. Xstatic  char Rcsid[] ="$Header: /mnt/ntape/RCS/dtree.c,v 1.2 84/04/23 10:33:41 root Exp $";
  266. X#endif /* S_IFLNK */
  267. X
  268. X#include    <stdio.h>
  269. X#include    <sys/types.h>
  270. X#include    <sys/stat.h>
  271. X#include    <time.h>
  272. X
  273. X#ifdef    STATS
  274. X# include    <pwd.h>
  275. X# include    <grp.h>
  276. X#endif    /* STATS */
  277. X
  278. X#ifdef    NEWDIR
  279. X# if    DIRENT
  280. X#  include    <dirent.h>
  281. X#  define    direct    dirent
  282. X# else
  283. X#  if    NDIR
  284. X#   include    <sys/ndir.h>
  285. X#  else
  286. X#   include    <sys/dir.h>
  287. X#  endif
  288. X# endif /* DIRENT */
  289. X#else
  290. X# include    <sys/dir.h>
  291. X#endif    /* NEWDIR */
  292. X
  293. X/* default column length when -v is given */
  294. X#ifdef unos
  295. X#define DEFCOLWID    30
  296. X#else
  297. X#define DEFCOLWID       14
  298. X#endif
  299. X
  300. X#include    <sys/param.h>    /* for MAXPATHLEN */
  301. X#ifndef MAXPATHLEN
  302. X# ifdef LPNMAX        /* Xenix from stdio.h */
  303. X#  define MAXPATHLEN (LPNMAX - 1)
  304. X# else
  305. X#  include <limits.h>    /* try somewhere else */
  306. X#  define MAXPATHLEN PATH_MAX
  307. X# endif
  308. X#endif
  309. X
  310. X#ifndef MAXNAMLEN    /* defined with NEWDIR routines */
  311. X# ifdef LFNMAX        /* Xenix again */
  312. X#  define MAXNAMLEN (LFNMAX - 1)
  313. X# else
  314. X#  define MAXNAMLEN      DEFCOLWID
  315. X# endif
  316. X#endif
  317. X
  318. X#define    DEPTH    10    /* maximum depth that dtree will go */
  319. X#define    INITIAL_ELEM    100    /* initial # of elements for list of files */
  320. X
  321. X#define    FFIRST    2    /* sort files first */
  322. X#define DFIRST    1    /* sort directories first */
  323. X#define    FAIL    -1    /* failure return status of sys calls */
  324. X#define    GREATER    1    /* return value of strcmp if arg1 > arg2 */
  325. X#define    LESSTHAN -1    /* return value of strcmp if arg1 < arg2 */
  326. X#define    SAME    0    /* return value of strcmp if arg1 == arg2 */
  327. X
  328. X#ifdef    STATS
  329. Xchar *getmode();
  330. Xchar *guid();
  331. Xchar *ggid();
  332. Xstruct passwd *getpwuid();
  333. Xstruct group *getgrgid();
  334. X#endif /* STATS */
  335. X
  336. X#ifdef    SYSV
  337. X#define    rindex    strrchr
  338. X#endif /* SYSV */
  339. X
  340. Xchar *getwd();
  341. Xchar *malloc();
  342. Xchar *realloc();
  343. Xchar *rindex();
  344. Xint qsort();
  345. Xlong time();
  346. X
  347. Xint compar();            /* comparison routine for qsort */
  348. Xchar *xmalloc();
  349. Xchar *xrealloc();
  350. X
  351. X#ifdef    SYSV
  352. X#define getwd(buf) getcwd((buf), MAXPATHLEN + 1)
  353. X#endif /* SYSV */
  354. X
  355. Xint    Index = 0;        /* current element of list[]    */
  356. Xint     CLength = 0;        /* max length of a column       */
  357. Xint    All = 0;        /* all != 0; list non-directory entries */
  358. Xint    File_dir = 0;        /* flag for how to sort */
  359. Xint    Sort = 1;        /* flag to cause sorting of entries */
  360. Xint    Point = 1;        /* skip point files if set    */
  361. Xint    Header = 0;        /* print verbose header */
  362. Xint    Maxes[DEPTH];        /* array keeps track of max length in columns */
  363. Xint    Level = 0;        /* counter for how deep we are    */
  364. Xint    Device;            /* device that we are starting tree on */
  365. Xint    Xdev = 1;        /* set to allow crossing of devices */
  366. Xint    Varspaces = 1;        /* set to allow compaction of column width */
  367. X#ifdef    STATS
  368. Xint    Gflag = 0;        /* set for group stats instead of owner */
  369. Xint    Longflg = 0;        /* set for long listing */
  370. Xint    Compact = 0;        /* set for shortened long listing */
  371. X#endif    /* STATS */
  372. Xstruct    stat Status;
  373. X#ifdef  S_IFLNK
  374. Xstruct  stat Lstat;   /* stat of link, if there is one */
  375. X#endif  /* S_IFLNK */
  376. X
  377. Xstruct entry {
  378. X    int next;            /* index to next element in list */
  379. X                    /* could be a ptr, but realloc() */
  380. X                    /* might screw us then */
  381. X#ifdef    STATS
  382. X    off_t    e_size;            /* size in blocks */
  383. X    unsigned short    e_mode;        /* file mode */
  384. X    short    e_uid;            /* uid of owner */
  385. X    short    e_gid;            /* gid of owner */
  386. X#endif    /* STATS */
  387. X    unsigned short dir : 1;        /* entry is a directory */
  388. X    unsigned short last : 1;    /* last entry in the dir. */
  389. X    unsigned short dev : 1;        /* set if same device as top */
  390. X    unsigned short end : 13;    /* index of last subdir entry*/
  391. X    char    e_name[MAXNAMLEN + 1];    /* name from directory entry */
  392. X} *List, *SaveList;
  393. X
  394. Xunsigned Size;                /* how big of space we've malloced */
  395. X
  396. Xchar    *Spaces;    /* used for output */
  397. Xchar    Buf1[BUFSIZ];    /* buffers for stdio stuff.  We don't want    */
  398. X#ifndef NEWDIR
  399. Xchar    Buf2[BUFSIZ];    /* anyone calling malloc, because then        */
  400. X            /* realloc() will have to move the whole list    */
  401. X#endif
  402. X
  403. Xmain(argc, argv)
  404. Xchar    **argv;
  405. Xint    argc;
  406. X{
  407. X    extern int optind;
  408. X    extern char *optarg;
  409. X    register int i;
  410. X    char    top[MAXPATHLEN + 1];    /* array for treetop name */
  411. X    char    home[MAXPATHLEN + 1];    /* starting dir for multiple trees */
  412. X    char    *ptr;
  413. X
  414. X    setbuf(stdout, Buf1);
  415. X
  416. X    while ((i = getopt (argc, argv,
  417. X#ifdef STATS
  418. X                "adfgHlnpsvxc:"
  419. X#else
  420. X                "adfHnpvxc:"
  421. X#endif /* STATS */
  422. X                )) != EOF) {
  423. X        switch (i) {
  424. X                case 'a':
  425. X                    All = 1;
  426. X                    break;
  427. X                case 'c':
  428. X                    CLength = atoi(optarg);
  429. X                    if (CLength > MAXNAMLEN)
  430. X                        CLength = MAXNAMLEN;
  431. X                    else if (CLength < 1)
  432. X                        CLength = DEFCOLWID;
  433. X                    break;
  434. X                case 'd':
  435. X                    File_dir = DFIRST;
  436. X                    break;
  437. X                case 'f':
  438. X                    File_dir = FFIRST;
  439. X                    break;
  440. X                case 'H':
  441. X                    Header = 1;
  442. X                    break;
  443. X                case 'n':
  444. X                    Sort = 0;
  445. X                    break;
  446. X                case 'p':
  447. X                    Point = 0;
  448. X                    break;
  449. X                case 'v':
  450. X                    Varspaces = 0;
  451. X                    break;
  452. X                case 'x':
  453. X                    Xdev = 0;
  454. X                    break;
  455. X#ifdef    STATS
  456. X                case 'g':
  457. X                    Gflag = 1;
  458. X                    break;
  459. X                case 'l':
  460. X                    Longflg = 1;
  461. X                    break;
  462. X                case 's':
  463. X                    Compact = 1;
  464. X                    break;
  465. X#endif    /* STATS */
  466. X                default:
  467. X                    fprintf(stderr,
  468. X#ifdef    STATS
  469. X        "Usage: dtree [-adfgHlnpsvx] [-c linelength] [directory ... ]\n"
  470. X#else    /* STATS */
  471. X        "Usage: dtree [-adfHnpvx] [-c linelength] [directory ... ]\n"
  472. X#endif    /* STATS */
  473. X                        );
  474. X                    exit(FAIL);
  475. X                }
  476. X    }
  477. X#ifdef    STATS
  478. X    if (Compact && !Gflag)
  479. X        Longflg = 1;
  480. X#endif    /* STATS */
  481. X    if (CLength == 0)
  482. X        CLength = Varspaces ? MAXNAMLEN : DEFCOLWID;
  483. X
  484. X    /* Establish where we are (our home base...) */
  485. X    if (getwd(home) == 0) {
  486. X        fprintf(stderr,
  487. X            "dtree: Cannot get initial directory: %s\n", home);
  488. X        exit(1);
  489. X    }
  490. X
  491. X    Spaces = xmalloc(MAXNAMLEN+2);
  492. X    for(i = 0; i <= MAXNAMLEN; i++)
  493. X        Spaces[i] = ' ';
  494. X    Spaces[i] = '\0';
  495. X
  496. X    /* Get initial Storage space */
  497. X    Size = sizeof(struct entry) * INITIAL_ELEM;
  498. X    SaveList = (struct entry *)xmalloc(Size);
  499. X
  500. X    /* adjust for no specified directory */
  501. X    if (optind == argc)
  502. X        argv[--optind] = ".";
  503. X
  504. X    if (Header)
  505. X        print_date();
  506. X
  507. X    /* walk down the rest of the args, treeing them one at at time */
  508. X    for (; optind < argc; optind++) {
  509. X        if (chdir(home) == -1) {
  510. X            fprintf(stderr, "dtree: Cannot change to initial directory ");
  511. X            perror(home);
  512. X            exit(1);
  513. X        }
  514. X        strncpy (top, argv[optind], MAXPATHLEN);
  515. X
  516. X        if (chdir(top) == FAIL) {
  517. X            fprintf(stderr, "dtree: Cannot change to top directory ");
  518. X            perror(top);
  519. X            continue;
  520. X        } else if (getwd(top) == 0) {
  521. X            fprintf(stderr,"dtree: Cannot get current directory: %s\n", top);
  522. X            continue;
  523. X        }
  524. X
  525. X        List = SaveList; Index = 0;
  526. X        ptr = rindex(top, '/');
  527. X
  528. X        if (!ptr || *++ptr == '\0')
  529. X            strncpy(List[Index].e_name, top, MAXNAMLEN);
  530. X        else
  531. X            strncpy(List[Index].e_name, ptr, MAXNAMLEN);
  532. X
  533. X        if(stat(top, &Status) == FAIL) {
  534. X            fprintf(stderr, "dtree: Cannot stat directory ");
  535. X            perror(top);
  536. X            continue;
  537. X        }
  538. X        Device = Status.st_dev;
  539. X        List[0].dir = 1;
  540. X        List[0].last = 1;
  541. X        List[0].next = 1;
  542. X#ifdef    STATS
  543. X        List[0].e_mode = Status.st_mode;
  544. X        List[0].e_uid = Status.st_uid;
  545. X        List[0].e_gid = Status.st_gid;
  546. X        List[0].e_size = Status.st_size;
  547. X#endif    /* STATS */
  548. X        Index = 1;
  549. X        for (i = 1; i < DEPTH; i++)
  550. X            Maxes[i] = 0;
  551. X        Maxes[0] = stln(List[0].e_name);
  552. X        Level = 1;
  553. X
  554. X        /* search the tree */
  555. X        List[0].end = t_search(top, &List[0]);
  556. X
  557. X        if (Index == 1)                /* empty tree */
  558. X            List[0].next = 0;
  559. X
  560. X        if (Header) {
  561. X        if (All)
  562. X            printf("\nDirectory structure and contents of %s\n", top);
  563. X        else
  564. X            printf("\nDirectory structure of %s\n", top);
  565. X        if (Point)
  566. X            printf("(excluding entries that begin with '.')\n");
  567. X        }
  568. X
  569. X        pt_tree();                /* print the tree */
  570. X    }
  571. X    exit(0) ;
  572. X}
  573. X
  574. X
  575. Xt_search(dir, addrs)
  576. Xchar *dir;
  577. Xstruct    entry *addrs;
  578. X{
  579. X    int    bsort;            /* index to begin sort */
  580. X    int    stmp;            /* save temporary index value */
  581. X    struct entry *sstep;        /* saved step in list */
  582. X    int    nitems;            /* # of items in this directory */
  583. X#ifdef    NEWDIR
  584. X    DIR    *dirp;            /* pointer to directory */
  585. X#else
  586. X    FILE    *dirp;
  587. X#endif
  588. X    char    sub[MAXNAMLEN+1];    /* used for subdirectory names */
  589. X    int    i;
  590. X#ifdef    NEWDIR
  591. X    struct direct *dp;
  592. X#else
  593. X    struct direct dirent;
  594. X    struct direct *dp = &dirent;
  595. X#endif    /* NEWDIR */
  596. X    int    n_subs = 0;
  597. X    int    tmp = 0;
  598. X
  599. X#ifdef    NEWDIR
  600. X    dirp = opendir(".");
  601. X#else
  602. X    dirp = fopen(".", "r");
  603. X#endif    /* NEWDIR */
  604. X    if (dirp == NULL) {
  605. X        fprintf(stderr, "dtree: Cannot open directory ");
  606. X        perror(dir);
  607. X        return(0);
  608. X    }
  609. X#ifndef    NEWDIR
  610. X    setbuf(dirp, Buf2);
  611. X#endif    /* NEWDIR */
  612. X
  613. X    bsort = Index;
  614. X    sstep = &List[bsort]; /* initialize sstep for for loop later on */
  615. X    nitems = Index;
  616. X    /* get the entries of the directory that we are interested in */
  617. X#ifndef    NEWDIR
  618. X    while (fread((char *)(dp), sizeof(struct direct), 1, dirp) == 1) {
  619. X#else
  620. X    while ((dp = readdir(dirp)) != NULL) {
  621. X#endif    /* NEWDIR */
  622. X
  623. X        if (dp->d_ino
  624. X#ifdef unos
  625. X            == -1
  626. X#else
  627. X            == 0
  628. X#endif /* unos */
  629. X            || (strcmp(dp->d_name, ".") == SAME)
  630. X            || (strcmp(dp->d_name, "..") == SAME)
  631. X            || (Point && dp->d_name[0] == '.'))
  632. X                continue;
  633. X
  634. X        strncpy(sub, dp->d_name, MAXNAMLEN);
  635. X#ifdef S_IFLNK
  636. X        if (lstat(sub,&Lstat) == FAIL) {
  637. X            fprintf(stderr, "dtree: In directory %s, cannot lstat entry ", dir);
  638. X            perror(sub);
  639. X            continue;
  640. X                }
  641. X#endif /* S_IFLNK */
  642. X        if (stat(sub, &Status) == FAIL) {
  643. X            fprintf(stderr, "dtree: In directory %s, cannot stat entry ", dir);
  644. X            perror(sub);
  645. X            continue;
  646. X        }
  647. X#ifdef S_IFLNK
  648. X        if (((Lstat.st_mode & S_IFMT) == S_IFLNK)  &&
  649. X            ((Status.st_mode & S_IFMT) == S_IFDIR)) 
  650. X                List[Index].dir = 0;    
  651. X        else if ((((Lstat.st_mode & S_IFMT) == S_IFLNK) &&
  652. X            ((Status.st_mode & S_IFMT) != S_IFDIR)) && (All)) 
  653. X                        List[Index].dir = 0;
  654. X#endif /* S_IFLNK */
  655. X        else if ((Status.st_mode & S_IFMT) == S_IFDIR)
  656. X            List[Index].dir = 1;
  657. X        else if (All)
  658. X            List[Index].dir = 0;
  659. X        else
  660. X            continue;
  661. X        strncpy(List[Index].e_name, dp->d_name, MAXNAMLEN);
  662. X        List[Index].last = 0;
  663. X        List[Index].end = 0;
  664. X#ifdef S_IFLNK
  665. X        if ((Lstat.st_mode & S_IFMT) == S_IFLNK) {
  666. X             List[Index].dev = (Device == Lstat.st_dev);
  667. X             List[Index].e_mode = Lstat.st_mode;
  668. X             List[Index].e_uid = Lstat.st_uid;
  669. X             List[Index].e_gid = Lstat.st_gid;
  670. X             List[Index].e_size = Lstat.st_size;
  671. X                }
  672. X                else {
  673. X#endif /* S_IFLNK */
  674. X             List[Index].dev = (Device == Status.st_dev);
  675. X#ifdef STATS
  676. X             List[Index].e_mode = Status.st_mode;
  677. X             List[Index].e_uid = Status.st_uid;
  678. X             List[Index].e_gid = Status.st_gid;
  679. X             List[Index].e_size = Status.st_size;
  680. X#endif /* STATS */
  681. X#ifdef S_IFLNK
  682. X                }
  683. X#endif /* S_IFLNK */
  684. X        if (stln(List[Index].e_name) > Maxes[Level])
  685. X            Maxes[Level] = stln(List[Index].e_name);
  686. X        ++Index;
  687. X        if (Index*sizeof(struct entry) >= Size) {
  688. X            Size += 20*sizeof(struct entry);
  689. X            List = (struct entry *)xrealloc((char *)List, Size);
  690. X        }
  691. X    }
  692. X#ifdef    NEWDIR
  693. X    closedir(dirp);
  694. X#else
  695. X    fclose(dirp);
  696. X#endif    /* NEWDIR */
  697. X
  698. X    nitems = Index - nitems;    /* nitems now contains the # of */
  699. X                    /* items in this dir, rather than */
  700. X                    /* # total items before this dir */
  701. X
  702. X    if (Sort)
  703. X        qsort(&List[bsort], nitems, sizeof(struct entry), compar);
  704. X
  705. X    List[Index-1].last = 1;    /* mark last item for this dir */
  706. X    n_subs = nitems;
  707. X    stmp = Index;
  708. X
  709. X    /* now walk through, and recurse on directory entries */
  710. X    /* sstep was initialized above */
  711. X
  712. X    for (i = 0; i < nitems; sstep = &List[stmp - nitems+(++i)]) {
  713. X        if (sstep->dir && (Xdev || sstep->dev)) {
  714. X            sstep->next = Index;
  715. X            strncpy(sub, sstep->e_name, MAXNAMLEN);
  716. X            tmp = n_subs;
  717. X            Level++;
  718. X            if (chdir(sub) == FAIL) {
  719. X                fprintf(stderr,
  720. X                    "dtree: Cannot change to directory %s/", dir);
  721. X                perror(sub);
  722. X            } else {
  723. X                n_subs += t_search(sub, sstep);
  724. X                if (chdir("..") == FAIL) {
  725. X                    fprintf(stderr,
  726. X                        "dtree: %s/%s lacks '..' entry\n",dir, sub);
  727. X                    exit(1);
  728. X                }
  729. X            }
  730. X            --Level;
  731. X            if (n_subs - tmp <= 0)
  732. X                sstep->next = 0;
  733. X            else
  734. X                --n_subs;
  735. X        }
  736. X        else
  737. X            sstep->next = 0;
  738. X    }
  739. X    addrs->end = (unsigned)n_subs;
  740. X    return(n_subs);
  741. X}
  742. X
  743. X/*
  744. X *    comparison routine for qsort
  745. X */
  746. X
  747. Xcompar(a, b)
  748. Xstruct entry *a, *b;
  749. X{
  750. X    if (!File_dir)        /* straight alphabetical */
  751. X        return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
  752. X
  753. X    /* sort alphabetically if both dirs or both not dirs */
  754. X
  755. X    if ((a->dir && b->dir) || (!a->dir && !b->dir))
  756. X        return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
  757. X
  758. X    if (File_dir == FFIRST) {    /* sort by files first */
  759. X        if (a->dir)
  760. X            return(GREATER);
  761. X        else
  762. X            return(LESSTHAN);
  763. X    }
  764. X
  765. X    if (a->dir)            /* sort by dir first */
  766. X        return(LESSTHAN);
  767. X    else
  768. X        return(GREATER);
  769. X}
  770. X
  771. X
  772. Xpt_tree()
  773. X{
  774. X    register int    i,j;
  775. X    struct entry *l;
  776. X    struct entry *hdr[DEPTH];
  777. X    int posit[DEPTH];        /* array of positions to print dirs */
  778. X    int con[DEPTH];            /* flags for connecting up tree */
  779. X    char    flag = 0;        /* flag to leave blank line after dir */
  780. X    struct    entry *stack[DEPTH];    /* save positions for changing levels */
  781. X    int    top = 0;        /* index to top of stack */
  782. X    int    count = 1;        /* count of line of output */
  783. X
  784. X    Level = 0;            /* initialize Level */
  785. X
  786. X    /* this loop appends each entry with dashes or spaces, for */
  787. X    /* directories or files respectively */
  788. X
  789. X    for (i = 0; i < Index; i++) {
  790. X        for (j = 0; j < MAXNAMLEN; j++) {
  791. X            if (!List[i].e_name[j])
  792. X                break;
  793. X        }
  794. X        if (List[i].dir) {
  795. X            for (; j < MAXNAMLEN; j++)
  796. X                List[i].e_name[j] = '-';
  797. X        } else {
  798. X            for (; j < MAXNAMLEN; j++)
  799. X                List[i].e_name[j] = ' ';
  800. X        }
  801. X    }
  802. X
  803. X    /* adjust the Maxes array according to the flags */
  804. X
  805. X    for (i = 0; i < DEPTH; i++) {
  806. X        if (Varspaces) {
  807. X            if (Maxes[i] > CLength )
  808. X                Maxes[i] = CLength;
  809. X        } else
  810. X            Maxes[i] = CLength;
  811. X    }
  812. X
  813. X    /* clear the connective and position flags */
  814. X
  815. X    for (i = 0; i < DEPTH; i++)
  816. X        con[i] = posit[i] = 0;
  817. X
  818. X    /* this is the main loop to print the tree structure. */
  819. X    l = &List[0];
  820. X    j = 0;
  821. X    for (;;) {
  822. X        /* directory entry, save it for later printing */
  823. X        if (l->dir != 0 && l->next != 0) {
  824. X            hdr[Level] = l;
  825. X            posit[Level] = count + (l->end + 1)/2 - 1;
  826. X            flag = 1;
  827. X            stack[top++] = l;
  828. X            l = &List[l->next];
  829. X            ++Level;
  830. X            continue;
  831. X        }
  832. X
  833. X#ifdef    STATS
  834. X    do_it_again:
  835. X#endif    /* STATS */
  836. X        /* print columns up to our entry */
  837. X        for (j = 0; j < (flag ? Level-1 : Level); j++) {
  838. X            if (!flag && posit[j] && posit[j] <= count) {
  839. X                /* time to print it */
  840. X                if (hdr[j]->e_name[CLength-1] != '-')
  841. X                    hdr[j]->e_name[CLength-1] = '*';
  842. X                printf("|-%.*s",Maxes[j],hdr[j]->e_name);
  843. X                posit[j] = 0;
  844. X                if (hdr[j]->last != 0)
  845. X                    con[j] = 0;
  846. X                else
  847. X                    con[j] = 1;
  848. X#ifdef    STATS
  849. X                if (Gflag || Longflg) {
  850. X                    if ((i = j+1) <= Level)
  851. X                    printf("| %.*s", Maxes[i], Spaces);
  852. X                    for (i++; i <= Level; i++) {
  853. X                    printf("%c %.*s",
  854. X                        (con[i] ? '|' : ' '),
  855. X                        Maxes[i], Spaces);
  856. X                    }
  857. X                    if (!Compact) {
  858. X                    printf("%s ", getmode(hdr[j]->e_mode));
  859. X                    if (Longflg)
  860. X                       printf("%8.8s ",guid(hdr[j]->e_uid));
  861. X                    if (Gflag)
  862. X                       printf("%8.8s ",ggid(hdr[j]->e_gid));
  863. X                    printf("%7ld\n",
  864. X                        (hdr[j]->e_size+511L)/512L);
  865. X                    } else {
  866. X                    printf(" %04o ",hdr[j]->e_mode & 07777);
  867. X                    if (Longflg)
  868. X                        printf("%5u ", hdr[j]->e_uid);
  869. X                    if (Gflag)
  870. X                        printf("%5u ", hdr[j]->e_gid);
  871. X                    printf("%7ld\n",
  872. X                        (hdr[j]->e_size+511L)/512L);
  873. X                    }
  874. X                    goto do_it_again;
  875. X                }
  876. X#endif    /* STATS */
  877. X            } else
  878. X                printf("%c %.*s", (con[j] ? '|' : ' '),
  879. X                    Maxes[j], Spaces);
  880. X        }
  881. X        if (flag) {    /* start of directory, so leave a blank line */
  882. X            printf(con[j] ? "|\n" : "\n");
  883. X            flag = 0;
  884. X            continue;
  885. X        } else {
  886. X                /* normal file name, print it out */
  887. X            if (l->e_name[CLength-1] != '-' &&
  888. X                l->e_name[CLength-1] != ' ')
  889. X                l->e_name[CLength-1] = '*';
  890. X            printf("|-%.*s",Maxes[Level],l->e_name);
  891. X            if (l->last) {
  892. X                con[j] = 0;
  893. X            } else {
  894. X                con[j] = 1;
  895. X            }
  896. X#ifdef    STATS
  897. X            if (Gflag || Longflg) {
  898. X                if (Compact) {
  899. X                    printf(" %04o ", l->e_mode & 07777);
  900. X                    if (Longflg)
  901. X                        printf("%5u ", l->e_uid);
  902. X                    if (Gflag)
  903. X                        printf("%5u ", l->e_gid);
  904. X                    printf("%7ld",
  905. X                        (l->e_size+511L)/512L);
  906. X                } else {
  907. X                    printf("%s ", getmode(l->e_mode));
  908. X                    if (Longflg)
  909. X                        printf("%8.8s ",guid(l->e_uid));
  910. X                    if (Gflag)
  911. X                        printf("%8.8s ",ggid(l->e_gid));
  912. X                    printf("%7ld",
  913. X                        (l->e_size+511L)/512L);
  914. X                }
  915. X            }
  916. X#endif    /* STATS */
  917. X        }
  918. X        printf("\n");
  919. X
  920. X        if (l->last) {
  921. X            /* walk back up */
  922. X            while (l->last) {
  923. X                --Level;
  924. X                if (--top <= 0)
  925. X                    return;
  926. X                l = stack[top];
  927. X            }
  928. X        }
  929. X        l = &l[1];
  930. X        ++count;
  931. X    }
  932. X}
  933. X
  934. X#ifdef    STATS
  935. X
  936. Xchar *
  937. Xguid(uid)
  938. Xshort uid;
  939. X{
  940. X    static char tb[10];
  941. X    struct passwd *pswd;
  942. X
  943. X    pswd = getpwuid(uid);
  944. X    if (pswd == NULL)
  945. X        sprintf(tb,"%u", uid);
  946. X    else
  947. X        sprintf(tb, "%8s", pswd->pw_name);
  948. X    return(tb);
  949. X}
  950. X
  951. Xchar *
  952. Xggid(gid)
  953. Xshort gid;
  954. X{
  955. X    static char tb[10];
  956. X    struct group *grp;
  957. X
  958. X    grp = getgrgid(gid);
  959. X    if (grp == NULL)
  960. X        sprintf(tb,"%u", gid);
  961. X    else
  962. X        sprintf(tb, "%8s", grp->gr_name);
  963. X    return(tb);
  964. X}
  965. X
  966. X/* take the mode and make it into a nice character string */
  967. X
  968. Xchar    *
  969. Xgetmode(p_mode)
  970. Xunsigned short p_mode;
  971. X{
  972. X    static char a_mode[16];
  973. X    register int    i = 0, j = 0;
  974. X
  975. X    a_mode[j++] = ' ';
  976. X
  977. X    switch (p_mode & S_IFMT) {
  978. X#ifdef S_IFLNK
  979. X    case S_IFLNK:
  980. X        a_mode[j++] = 'l';
  981. X        break;
  982. X#endif /* S_IFLNK */
  983. X    case S_IFDIR:
  984. X        a_mode[j++] = 'd';
  985. X        break;
  986. X#ifdef    S_IFMPC        /* defined in stat.h if you have MPX files */
  987. X    case S_IFMPC:
  988. X        a_mode[j-1] = 'm';
  989. X        /* FALL THROUGH */
  990. X#endif    /* S_IFMPC */
  991. X    case S_IFCHR:
  992. X        a_mode[j++] = 'c';
  993. X        break;
  994. X#ifdef    S_IFMPB        /* defined in stat.h if you have MPX files */
  995. X    case S_IFMPB:
  996. X        a_mode[j-1] = 'm';
  997. X        /* FALL THROUGH */
  998. X#endif    /* S_IFMPB */
  999. X    case S_IFBLK:
  1000. X        a_mode[j++] = 'b';
  1001. X        break;
  1002. X    case S_IFREG:
  1003. X    default:
  1004. X        a_mode[j++] = (p_mode & S_ISVTX) ? 't' : ' ';
  1005. X        break;
  1006. X    }
  1007. X    a_mode[j++] = ' ';
  1008. X    for( i = 0;i<3;i++ ) {
  1009. X        a_mode[j++] = (p_mode<<(3*i) & S_IREAD) ? 'r' : '-';
  1010. X        a_mode[j++] = (p_mode<<(3*i) & S_IWRITE) ? 'w' : '-';
  1011. X        a_mode[j++] = (i<2 && (p_mode<<i & S_ISUID)) ? 's' :
  1012. X                  ((p_mode<<(3*i) & S_IEXEC ) ? 'x' : '-');
  1013. X        a_mode[j++] = ' ';
  1014. X    }
  1015. X    a_mode[j] = '\0';
  1016. X    return(a_mode);
  1017. X}
  1018. X#endif
  1019. X
  1020. X/* like strlen, but returns length up to MAXNAMLEN-1 */
  1021. Xstln(st)
  1022. Xregister char *st;
  1023. X{
  1024. X    register int t;
  1025. X
  1026. X    for (t=0; t<MAXNAMLEN-1; ++t)
  1027. X        if (!st[t])
  1028. X            return (++t);
  1029. X    return (++t);
  1030. X}
  1031. X
  1032. Xprint_date()
  1033. X{
  1034. X    long now;
  1035. X
  1036. X    time(&now);
  1037. X    printf ("%s", ctime(&now));
  1038. X}
  1039. X
  1040. Xvoid
  1041. Xmemory_out()
  1042. X{
  1043. X    fprintf(stderr, "dtree: Virtual memory exhausted\n");
  1044. X    exit(1);
  1045. X}
  1046. X
  1047. X/* Allocate `size' bytes of memory dynamically, with error checking.  */
  1048. X
  1049. Xchar *
  1050. Xxmalloc (size)
  1051. Xunsigned size;
  1052. X{
  1053. X    char *ptr;
  1054. X
  1055. X    ptr = malloc (size);
  1056. X    if (ptr == 0 && size != 0)
  1057. X        memory_out ();
  1058. X    return ptr;
  1059. X}
  1060. X
  1061. X/* Change the size of an allocated block of memory `ptr' to `size' bytes,
  1062. X   with error checking.
  1063. X   If `ptr' is NULL, run xmalloc.
  1064. X   If `size' is 0, run free and return NULL.  */
  1065. X
  1066. Xchar *
  1067. Xxrealloc (ptr, size)
  1068. Xchar *ptr;
  1069. Xunsigned size;
  1070. X{
  1071. X    if (ptr == 0)
  1072. X        return xmalloc (size);
  1073. X    if (size == 0) {
  1074. X        free (ptr);
  1075. X        return 0;
  1076. X    }
  1077. X    ptr = realloc (ptr, size);
  1078. X    if (ptr == 0 && size != 0)
  1079. X        memory_out ();
  1080. X    return ptr;
  1081. X}
  1082. END_OF_FILE
  1083. if test 21819 -ne `wc -c <'dtree.c'`; then
  1084.     echo shar: \"'dtree.c'\" unpacked with wrong size!
  1085. fi
  1086. # end of 'dtree.c'
  1087. fi
  1088. if test -f 'getcwd.c' -a "${1}" != "-c" ; then 
  1089.   echo shar: Will not clobber existing file \"'getcwd.c'\"
  1090. else
  1091. echo shar: Extracting \"'getcwd.c'\" \(5247 characters\)
  1092. sed "s/^X//" >'getcwd.c' <<'END_OF_FILE'
  1093. X/*
  1094. X    getcwd -- get current working directory name (POSIX and SVID compatible)
  1095. X
  1096. X    last edit:    21-Sep-1987    D A Gwyn
  1097. X
  1098. X    This public-domain getcwd() routine can be used to replace the UNIX
  1099. X    System V library routine (which uses popen() to capture the output of
  1100. X    the "pwd" command).  Once that is done, "pwd" can be reimplemented as
  1101. X    just puts(getcwd()).
  1102. X
  1103. X    This implementation depends on every directory having entries for
  1104. X    "." and "..".  It also depends on the internals of the <dirent.h>
  1105. X    data structures to some degree.
  1106. X
  1107. X    I considered using chdir() to ascend the hierarchy, followed by a
  1108. X    final chdir() to the path being returned by getcwd() to restore the
  1109. X    location, but decided that error recovery was too difficult that way.
  1110. X    The algorithm I settled on was inspired by my rewrite of the "pwd"
  1111. X    utility, combined with the dotdots[] array trick from the SVR2 shell.
  1112. X*/
  1113. X#include    <sys/types.h>
  1114. X#include    <sys/stat.h>
  1115. X#include    <string.h>
  1116. X#include    <dirent.h>
  1117. X#include    <errno.h>
  1118. X
  1119. Xtypedef char    *pointer;        /* (void *) if you have it */
  1120. X
  1121. Xextern void    free();
  1122. Xextern pointer    malloc();
  1123. Xextern int    fstat(), stat();
  1124. X
  1125. Xextern int    errno;            /* normally done by <errno.h> */
  1126. X
  1127. X#ifndef NULL
  1128. X#define    NULL    0            /* amorphous null pointer constant */
  1129. X#endif
  1130. X
  1131. X#ifndef NAME_MAX
  1132. X#define    NAME_MAX    255        /* maximum directory entry size */
  1133. X#endif
  1134. X
  1135. Xchar    *
  1136. Xgetcwd( buf, size )            /* returns pointer to CWD pathname */
  1137. X    char        *buf;        /* where to put name (NULL to malloc) */
  1138. X    int        size;        /* size of buf[] or malloc()ed memory */
  1139. X    {
  1140. X    static char    dotdots[] =
  1141. X"../../../../../../../../../../../../../../../../../../../../../../../../../..";
  1142. X    char         *dotdot;    /* -> dotdots[.], right to left */
  1143. X    DIR        *dirp;        /* -> parent directory stream */
  1144. X    struct dirent    *dir;        /* -> directory entry */
  1145. X    struct stat    stat1, stat2;    /* info from stat() */
  1146. X    struct stat    *d = &stat1;    /* -> info about "." */
  1147. X    struct stat    *dd = &stat2;    /* -> info about ".." */
  1148. X    register char    *buffer;    /* local copy of buf, or malloc()ed */
  1149. X    char        *bufend;    /* -> buffer[size] */
  1150. X    register char    *endp;        /* -> end of reversed string */
  1151. X    register char    *dname;        /* entry name ("" for root) */
  1152. X    int        serrno = errno;    /* save entry errno */
  1153. X
  1154. X    if ( size == 0 )
  1155. X        {
  1156. X        errno = EINVAL;        /* invalid argument */
  1157. X        return NULL;
  1158. X        }
  1159. X
  1160. X    if ( (buffer = buf) == NULL    /* wants us to malloc() the string */
  1161. X      && (buffer = (char *)malloc( (unsigned)size )) == NULL
  1162. X       )    {
  1163. X        errno = ENOMEM;        /* cannot malloc() specified size */
  1164. X        return NULL;
  1165. X        }
  1166. X
  1167. X    if ( stat( ".", dd ) != 0 )    /* prime the pump */
  1168. X        goto error;        /* errno already set */
  1169. X
  1170. X    endp = buffer;            /* initially, empty string */
  1171. X    bufend = &buffer[size];
  1172. X
  1173. X    for ( dotdot = &dotdots[sizeof(dotdots)]; dotdot != dotdots; )
  1174. X        {
  1175. X        dotdot -= 3;        /* include one more "/.." section */
  1176. X                    /* (first time is actually "..") */
  1177. X
  1178. X        /* swap stat() info buffers */
  1179. X        {
  1180. X        register struct stat    *temp = d;
  1181. X
  1182. X        d = dd;            /* new current dir is old parent dir */
  1183. X        dd = temp;
  1184. X        }
  1185. X
  1186. X        if ( (dirp = opendir( dotdot )) == NULL )    /* new parent */
  1187. X            goto error;    /* errno already set */
  1188. X
  1189. X        if ( fstat( dirp->dd_fd, dd ) != 0 )
  1190. X            {
  1191. X            serrno = errno;    /* set by fstat() */
  1192. X            (void)closedir( dirp );
  1193. X            errno = serrno;    /* in case closedir() clobbered it */
  1194. X            goto error;
  1195. X            }
  1196. X
  1197. X        if ( d->st_dev == dd->st_dev )
  1198. X            {        /* not crossing a mount point */
  1199. X            if ( d->st_ino == dd->st_ino )
  1200. X                {    /* root directory */
  1201. X                dname = "";
  1202. X                goto append;
  1203. X                }
  1204. X
  1205. X            do
  1206. X                if ( (dir = readdir( dirp )) == NULL )
  1207. X                    {
  1208. X                    (void)closedir( dirp );
  1209. X                    errno = ENOENT;    /* missing entry */
  1210. X                    goto error;
  1211. X                    }
  1212. X            while ( dir->d_ino != d->st_ino );
  1213. X            }
  1214. X        else    {        /* crossing a mount point */
  1215. X            struct stat    t;    /* info re. test entry */
  1216. X            char        name[sizeof(dotdots) + 1 + NAME_MAX];
  1217. X
  1218. X            (void)strcpy( name, dotdot );
  1219. X            dname = &name[strlen( name )];
  1220. X            *dname++ = '/';
  1221. X
  1222. X            do    {
  1223. X                if ( (dir = readdir( dirp )) == NULL )
  1224. X                    {
  1225. X                    (void)closedir( dirp );
  1226. X                    errno = ENOENT;    /* missing entry */
  1227. X                    goto error;
  1228. X                    }
  1229. X
  1230. X                (void)strcpy( dname, dir->d_name );
  1231. X                /* must fit if NAME_MAX is not a lie */
  1232. X                }
  1233. X            while ( stat( name, &t ) != 0
  1234. X                 || t.st_ino != d->st_ino
  1235. X                 || t.st_dev != d->st_dev
  1236. X                  );
  1237. X            }
  1238. X
  1239. X        dname = dir->d_name;
  1240. X
  1241. X        /* append "/" and reversed dname string onto buffer */
  1242. X    append:
  1243. X        if ( endp != buffer    /* avoid trailing / in final name */
  1244. X          || dname[0] == '\0'    /* but allow "/" when CWD is root */
  1245. X           )
  1246. X            *endp++ = '/';
  1247. X
  1248. X        {
  1249. X        register char    *app;    /* traverses dname string */
  1250. X
  1251. X        for ( app = dname; *app != '\0'; ++app )
  1252. X            ;
  1253. X
  1254. X        if ( app - dname >= bufend - endp )
  1255. X            {
  1256. X            (void)closedir( dirp );
  1257. X            errno = ERANGE;    /* won't fit allotted space */
  1258. X            goto error;
  1259. X            }
  1260. X
  1261. X        while ( app != dname )
  1262. X            *endp++ = *--app;
  1263. X        }
  1264. X
  1265. X        (void)closedir( dirp );
  1266. X
  1267. X        if ( dname[0] == '\0' )    /* reached root; wrap it up */
  1268. X            {
  1269. X            register char    *startp;    /* -> buffer[.] */
  1270. X
  1271. X            *endp = '\0';    /* plant null terminator */
  1272. X
  1273. X            /* straighten out reversed pathname string */
  1274. X            for ( startp = buffer; --endp > startp; ++startp )
  1275. X                {
  1276. X                char    temp = *endp;
  1277. X
  1278. X                *endp = *startp;
  1279. X                *startp = temp;
  1280. X                }
  1281. X
  1282. X            errno = serrno;    /* restore entry errno */
  1283. X            return buffer;
  1284. X            }
  1285. X        }
  1286. X
  1287. X    errno = ENOMEM;            /* actually, algorithm failure */
  1288. X
  1289. X    error:
  1290. X    if ( buf == NULL )
  1291. X        free( (pointer)buffer );
  1292. X
  1293. X    return NULL;
  1294. X    }
  1295. X
  1296. END_OF_FILE
  1297. if test 5247 -ne `wc -c <'getcwd.c'`; then
  1298.     echo shar: \"'getcwd.c'\" unpacked with wrong size!
  1299. fi
  1300. # end of 'getcwd.c'
  1301. fi
  1302. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  1303.   echo shar: Will not clobber existing file \"'Makefile'\"
  1304. else
  1305. echo shar: Extracting \"'Makefile'\" \(728 characters\)
  1306. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  1307. X# Makefile for dtree
  1308. X
  1309. X# Things that might go in DEFS:
  1310. X# -DSTATS -DNEWDIR -DDIRENT -DNDIR -DSYSV
  1311. XDEFS = -DSTATS -DNEWDIR -DDIRENT
  1312. XCFLAGS = $(DEFS) -O
  1313. XLDFLAGS = -s
  1314. XLIBS = # For Xenix use -lx with -DNDIR
  1315. X
  1316. XBINDIR = /usr/local/bin
  1317. XMANDIR = /usr/local/man/man1
  1318. X
  1319. XOBJECTS = dtree.o #getcwd.o
  1320. X
  1321. XARCH_FILES = README dtree.1 dtree.c getcwd.c Makefile
  1322. X
  1323. Xall: dtree
  1324. X
  1325. Xdtree: $(OBJECTS)
  1326. X    $(CC) -o dtree $(LDFLAGS) $(OBJECTS) $(LIBS)
  1327. X
  1328. Xinstall: dtree dtree.1
  1329. X    cp dtree $(BINDIR)
  1330. X    cp dtree.1 $(MANDIR)
  1331. X
  1332. Xlint: dtree.c
  1333. X    lint $(DEFS) dtree.c
  1334. X
  1335. Xshar: $(ARCH_FILES)
  1336. X    shar $(ARCH_FILES) > dtree.shar
  1337. X
  1338. Xdist: dtree.tar.Z
  1339. X
  1340. Xtar: dtree.tar.Z
  1341. X
  1342. Xdtree.tar.Z: $(ARCH_FILES)
  1343. X    tar cf - $(ARCH_FILES) | compress > dtree.tar.Z
  1344. X
  1345. Xclean:
  1346. X    rm -f dtree *.o core tags a.out
  1347. END_OF_FILE
  1348. if test 728 -ne `wc -c <'Makefile'`; then
  1349.     echo shar: \"'Makefile'\" unpacked with wrong size!
  1350. fi
  1351. # end of 'Makefile'
  1352. fi
  1353. echo shar: End of shell archive.
  1354. exit 0
  1355.  
  1356.